<template>
  <div class="scroll-table">
    <div
      ref="scroll-table"
      class="scroll-table-wrapper"
      :style="{
        height: `${height + 32}px`
      }">

      <div
        class="scroll-tableTh"
        :style="{
          width: `${this.tableWidth}px`,
          border: border ? `1px solid ${borderColor}` : 'none'
        }">
        <!-- theadCenter -->
        <table
          ref="warpperTh"
          class="scroll-tableThCenter">
          <thead>
            <tr>
              <td
                v-for="item in thead"
                class="th"
                :class="item.type ? item.type : 'text'"
                :style="{
                  width: `${item.width}px`,
                  textAlign: item.align,
                  color: thColor,
                  backgroundColor: thBgColor,
                  borderRight: border ? `1px solid ${borderColor}` : 'none',
                  visibility: item.fixed ? 'hidden' : ''
                }">
                <div v-if="item.type === 'index'">
                  #
                </div>
                <div v-else-if="item.type === 'selection'">
                  <Checkbox v-model="allChose" @on-change="allChoseChange"></Checkbox>
                </div>
                <div v-else>
                  {{item.title || '#'}}
                </div>
              </td>
            </tr>
          </thead>
        </table>

        <!-- theadLeft -->
        <div
          v-if="theadLeft.length"
          class="scroll-tableThLeft"
          :style="{
            width: `${leftWidth}px`
          }">
          <table class="scroll-tableLeftTh">
            <thead>
              <tr>
                <td
                  v-for="item in theadLeft"
                  class="th"
                  :class="item.type ? item.type : 'text'"
                  :style="{
                    width: `${item.width}px`,
                    textAlign: item.align,
                    color: thColor,
                    backgroundColor: thBgColor,
                    borderRight: border ? `1px solid ${borderColor}` : 'none'
                  }">
                  <div v-if="item.type === 'index'">
                    #
                  </div>
                  <div v-else-if="item.type === 'selection'">
                    <Checkbox v-model="allChose" @on-change="allChoseChange"></Checkbox>
                  </div>
                  <div v-else>
                    {{item.title || '#'}}
                  </div>
                </td>
              </tr>
            </thead>
          </table>
        </div>

        <!-- theadRight -->
        <div
          v-if="theadRight.length"
          class="scroll-tableThRight"
          :style="{
            width: `${rightWidth}px`
          }">
          <table class="scroll-tableRightTh">
            <thead>
              <tr>
                <td
                  v-for="item in theadRight"
                  class="th"
                  :class="item.type ? item.type : 'text'"
                  :style="{
                    width: `${item.width}px`,
                    textAlign: item.align,
                    color: thColor,
                    backgroundColor: thBgColor,
                    borderRight: border ? `1px solid ${borderColor}` : 'none'
                  }">
                  <div v-if="item.type === 'index'">
                    #
                  </div>
                  <div v-else-if="item.type === 'selection'">
                    <Checkbox v-model="allChose" @on-change="allChoseChange"></Checkbox>
                  </div>
                  <div v-else>
                    {{item.title || '#'}}
                  </div>
                </td>
              </tr>
            </thead>
          </table>
        </div>

      </div>

      <!-- tbody -->
      <div
        class="scroll-tableTb"
        :style="{
          border: border ? `1px solid ${borderColor}` : 'none',
          borderTop: 'none'
        }">
        <div v-if="!data.length" class="no-data">
          暂无数据
        </div>

        <div
          v-else
          ref="xScroll-wrapper"
          class="data"
          :style="{
            height: `${height}px`,
            paddingBottom: isNeedXscroll.bol ? `${scrollWidth}px` : 0
          }">
          <Scroll
            ref="scroll"
            :width="scrollWidth"
            :bgColor="scrollBgColor"
            :color="scrollColor"
            :hoverColor="scrollHoverColor"
            :isNeedPad="false"
            :data="tbody"
            @showScrollChange="yScrollChange">
            <div class="scroll-table-wrapper">

              <table
                ref="warpperTb"
                class="scroll-tableTb-wrapper">

                <tbody
                  :style="{
                    backgroundColor: tbBgColor
                  }">
                  <tr
                    v-for="(item, index) in tbody"
                    class="tb"
                    :style="{
                      color: tbColor,
                      borderBottom: border ? `1px solid ${borderColor}` : 'none',
                      backgroundColor: item._highlight ? highlightRowColor : (isHoverHightlight && item._isHover ? highlightRowColor : (stripe && index % 2 === 1 ? stripeColor : ''))
                    }"
                    @click="rowClick(item)"
                    @mouseenter="trMouseEnter(item)"
                    @mouseleave="trMouseLeave(item)">
                    <td
                      v-for="items in thead"
                      class="tb-item"
                      :class="items.type ? items.type : 'text'"
                      :style="{
                        width: `${items.width}px`,
                        textAlign: items.align,
                        borderRight: border ? `1px solid ${borderColor}` : 'none',
                        visibility: items.fixed ? 'hidden' : ''
                      }">
                      <Cell
                        v-if="items.render"
                        :row="item"
                        :index="index"
                        :column="items"
                        :render="items.render" />
                      <div v-else-if="items.type === 'index'">
                        {{index + 1}}
                      </div>
                      <div v-else-if="items.type === 'selection'">
                        <Checkbox v-model="item['_checked']" @click.native.stop @on-change="choseChange"></Checkbox>
                      </div>
                      <div v-else class="text-wrapper" :title="item[items.key]">
                        {{item[items.key]}}
                      </div>
                    </td>
                  </tr>
                </tbody>
              </table>

              <div
                class="scroll-tableLeft-wrapper"
                :style="{
                  width: `${leftWidth}px`
                }">
                <table
                  class="scroll-tableLeft-table"
                  :style="{
                    width: `${tableWidth}px`
                  }">
                  <tbody
                    :style="{
                      backgroundColor: tbBgColor
                    }">
                    <tr
                      v-for="(item, index) in tbody"
                      class="tb"
                      :style="{
                        color: tbColor,
                        borderBottom: border ? `1px solid ${borderColor}` : 'none',
                        backgroundColor: item._highlight ? highlightRowColor : (isHoverHightlight && item._isHover ? highlightRowColor : (stripe && index % 2 === 1 ? stripeColor : ''))
                      }"
                      @click="rowClick(item)"
                      @mouseenter="trMouseEnter(item)"
                      @mouseleave="trMouseLeave(item)">
                      <td
                        v-for="items in thead"
                        class="tb-item"
                        :class="items.type ? items.type : 'text'"
                        :style="{
                          width: `${items.width}px`,
                          textAlign: items.align,
                          borderRight: border ? `1px solid ${borderColor}` : 'none'
                        }">
                        <Cell
                          v-if="items.render"
                          :row="item"
                          :index="index"
                          :column="items"
                          :render="items.render" />
                        <div v-else-if="items.type === 'index'">
                          {{index + 1}}
                        </div>
                        <div v-else-if="items.type === 'selection'">
                          <Checkbox v-model="item['_checked']" @click.native.stop @on-change="choseChange"></Checkbox>
                        </div>
                        <div v-else class="text-wrapper" :title="item[items.key]">
                          {{item[items.key]}}
                        </div>
                      </td>
                    </tr>
                  </tbody>
                </table>
              </div>

              <div
                class="scroll-tableRight-wrapper"
                :style="{
                  width: `${rightWidth}px`
                }">
                <table
                  class="scroll-tableRight-table"
                  :style="{
                    width: `${tableWidth}px`
                  }">
                  <tbody
                    :style="{
                      backgroundColor: tbBgColor
                    }">
                    <tr
                      v-for="(item, index) in tbody"
                      class="tb"
                      :style="{
                        color: tbColor,
                        borderBottom: border ? `1px solid ${borderColor}` : 'none',
                        backgroundColor: item._highlight ? highlightRowColor : (isHoverHightlight && item._isHover ? highlightRowColor : (stripe && index % 2 === 1 ? stripeColor : ''))
                      }"
                      @click="rowClick(item)"
                      @mouseenter="trMouseEnter(item)"
                      @mouseleave="trMouseLeave(item)">
                      <td
                        v-for="items in theadRight"
                        class="tb-item"
                        :class="items.type ? items.type : 'text'"
                        :style="{
                          width: `${items.width}px`,
                          textAlign: items.align,
                          borderRight: border ? `1px solid ${borderColor}` : 'none'
                        }">
                        <Cell
                          v-if="items.render"
                          :row="item"
                          :index="index"
                          :column="items"
                          :render="items.render" />
                        <div v-else-if="items.type === 'index'">
                          {{index + 1}}
                        </div>
                        <div v-else-if="items.type === 'selection'">
                          <Checkbox v-model="item['_checked']" @click.native.stop @on-change="choseChange"></Checkbox>
                        </div>
                        <div v-else class="text-wrapper" :title="item[items.key]">
                          {{item[items.key]}}
                        </div>
                      </td>
                    </tr>
                  </tbody>
                </table>
              </div>

            </div>
          </Scroll>

          <div
            v-show="isNeedXscroll.bol"
            ref="scroll-table-xScroll"
            class="scroll-table-xScroll"
            :style="{
              height: `${scrollWidth}px`,
              backgroundColor: scrollBgColor
            }">
            <div
              ref="xScroll-move"
              class="xScroll-move"
              :style="{
                backgroundColor: scrollColor
              }"
              @mousedown="scrollDown"
              @mouseenter="scrollEnter"
              @mouseleave="scrollLeave"></div>
          </div>
        </div>

      </div>

    </div>

    <!-- loading -->
    <div class="scroll-tableLoading" v-show="loading">
      <Loading v-if="!$slots.loading" />
      <slot v-else name="loading"></slot>
    </div>
  </div>
</template>

<script>
import Scroll from '../scroll/scroll'
import Loading from '../loading/loading'
import Cell from './expand'
import { _prefixStyle, _CancelBubble } from '../../common'

const userSelect = _prefixStyle('user-select')

export default {
  props: {
    columns: {
      type: Array,
      default: () => []
    },
    data: {
      type: Array,
      default: () => []
    },
    maxHeight: {
      type: [Number, String]
    },
    thColor: {
      type: String,
      default: '#515a6e'
    },
    tbColor: {
      type: String,
      default: '#515a6e'
    },
    thBgColor: {
      type: String,
      default: '#f8f8f9'
    },
    tbBgColor: {
      type: String,
      default: 'white'
    },
    border: {
      type: Boolean,
      default: false
    },
    borderColor: {
      type: String,
      default: '#e8eaec'
    },
    stripe: {
      type: Boolean,
      default: false
    },
    stripeColor: {
      type: String,
      default: '#f8f8f9'
    },
    scrollWidth: {
      type: String,
      default: '5'
    },
    scrollBgColor: {
      type: String,
      default: 'rgba(27, 56, 130, 0)'
    },
    scrollColor: {
      type: String,
      default: 'rgb(181, 181, 181)'
    },
    scrollHoverColor: {
      type: String,
      default: 'gray'
    },
    loading: {
      type: Boolean,
      default: false
    },
    isHoverHightlight: {
      type: Boolean,
      default: false
    },
    highlightRow: {
      type: Boolean,
      default: false
    },
    highlightRowColor: {
      type: String,
      default: '#ebf7ff'
    }
  },
  components: {
    Scroll,
    Loading,
    Cell
  },
  computed: {
    isNeedXscroll () {
      let width = 0

      this.columns.map(item => {
        if (item.width) {
          width += item.width
        }
      })

      if (width >= this.tableWidth && this.data.length) {
        return { bol: true, width }
      }

      return { bol: false, width }
    },
    leftWidth () {
      let index = 0

      if (!this.theadLeft.length) {
        return index
      }

      this.theadLeft.map(item => {
        if (item.fixed === 'left' && item.width) {
          index += item.width
        }
      })

      return Number(index)
    },
    rightWidth () {
      let index = 0

      if (!this.theadRight.length) {
        return index
      }

      this.theadRight.map(item => {
        if (item.fixed === 'right' && item.width) {
          index += item.width
        }
      })

      return Number(index)
    },
    height () {
      if (this.tbody.length === 0) {
        return 40
      }

      if (this.tbody.length * 40 > Number(this.maxHeight) - 32) {
        return Number(this.maxHeight) - 32
      } else {
        if (this.isNeedXscroll.bol) {
          return this.tbody.length * 40 + Number(this.scrollWidth)
        } else {
          return this.tbody.length * 40
        }
      }
    }
  },
  watch: {
    columns () {
      this.initColumns()
    },
    data () {
      this.initData()
      this.initXscroll()
    }
  },
  created () {
    if (!this.maxHeight) {
      throw new Error('必须传入最大高度')
    }
  },
  mounted () {
    setTimeout(() => {
      this.initTable()
      this.initColumns()
      this.initData()
      this.initXscroll()
    }, 20)
  },
  data () {
    return {
      yIsShowScroll: false,
      tableWidth: 0,
      allChose: false,
      thead: [],
      theadLeft: [],
      theadRight: [],
      tbody: []
    }
  },
  methods: {
    rowClick (row) {
      if (!row['_highlight']) {
        this.tbody.map(item => {
          item['_highlight'] = false
        })

        row['_highlight'] = true
      }

      const cloneRow = JSON.parse(JSON.stringify(row))
      delete cloneRow['_checked']
      delete cloneRow['_highlight']

      this.$emit('on-row-click', cloneRow)
    },
    trMouseEnter (row) {
      if (!this.isHoverHightlight) {
        return
      }
      if (!row['_isHover']) {
        row['_isHover'] = true
      }
    },
    trMouseLeave (row) {
      if (!this.isHoverHightlight) {
        return
      }
      if (row['_isHover']) {
        row['_isHover'] = false
      }
    },
    choseChange () {
      let tbody = JSON.parse(JSON.stringify(this.tbody))
      tbody = tbody.filter(item => item['_checked'])

      tbody.map(item => {
        this.$delete(item, '_checked')
        this.$delete(item, '_highlight')
      })

      this.$emit('on-selection-change', tbody)
    },
    allChoseChange (value) {
      this.tbody.map(item => {
        item['_checked'] = value
      })

      const tbody = JSON.parse(JSON.stringify(this.tbody))
      tbody.map(item => {
        this.$delete(item, '_checked')
        this.$delete(item, '_highlight')
      })

      if (value) {
        this.$emit('on-select-all', tbody)
        this.$emit('on-selection-change', tbody)
      } else {
        this.$emit('on-select-all', [])
        this.$emit('on-selection-change', [])
      }
    },
    scrollDown (event) {
      if (!this.isNeedXscroll.bol) {
        return
      }

      let startX = event.clientX - this.scrollMove.offsetLeft
      document.onmousemove = (event) => {
        this.HTML.style[userSelect] = 'none'
        this.HTML.style['cursor'] = 'default'

        let X = event.clientX - startX

        if (X < 0) {
          X = 0
        }

        if (X > this.tbScroll.offsetWidth - this.scrollMove.offsetWidth) {
          X = this.tbScroll.offsetWidth - this.scrollMove.offsetWidth
        }

        this.scrollMove.style.left = `${X}px`
        this.warpperTb.style.left = `${Math.round(-this.isNeedXscroll.width * (X / this.tableWidth))}px`
        this.warpperTh.style.left = `${Math.round(-this.isNeedXscroll.width * (X / this.tableWidth))}px`
      }
      document.onmouseup = () => {
        this.HTML.style[userSelect] = ''
        this.HTML.style['cursor'] = ''
        document.onmousemove = null
      }
    },
    scrollEnter () {
      this.scrollMove.style.backgroundColor = this.scrollHoverColor
    },
    scrollLeave () {
      this.scrollMove.style.backgroundColor = this.scrollColor
    },
    scrollWheel (event, down) {
      if (this.yIsShowScroll || !this.isNeedXscroll.bol) {
        return
      }

      let wheel = (event.wheelDelta / 120) || -(event.detail / 3)

      // let smL = this.scrollMove.offsetLeft
      let swL = this.warpperTh.offsetLeft

      let swX = swL + (wheel * 40)
      let smX = -swX / this.isNeedXscroll.width * this.tableWidth

      if (smX < 0) {
        smX = 0
      }

      if (smX > this.tableWidth - this.scrollMove.offsetWidth) {
        smX = this.tableWidth - this.scrollMove.offsetWidth
      }

      if (swX < this.tableWidth - this.isNeedXscroll.width) {
        swX = this.tableWidth - this.isNeedXscroll.width
      }

      if (swX > 0) {
        swX = 0
      }
      this.scrollMove.style.left = `${smX}px`
      this.warpperTh.style.left = `${swX}px`
      this.warpperTb.style.left = `${swX}px`

      _CancelBubble(event)
    },
    onmouseWheel (obj, cbfn) { // 鼠标滚轮兼容事件
      var down = true
      if (window.navigator.userAgent.indexOf('Firefox') > -1) {
        obj.removeEventListener('DOMMouseScroll', fn)
        obj.addEventListener('DOMMouseScroll', fn, false)
      } else {
        obj.onmousewheel = fn
      }
      const vm = this

      function fn (event) {
        var e = event || window.event
        if (e.detail) {
          down = e.detail > 0
        } else {
          down = e.wheelDelta < 0
        }
        cbfn.call(obj, e, down)
        if (vm.isNeedXscroll.bol) {
          if (window.event.stopPropagation) {
            window.event.stopPropagation()
          } else {
            window.event.cancelBubble = true
          }
        }

        if (e.preventDefault) {
          e.preventDefault()
        } else {
          window.event.returnValue = false
        }
        return false
      }
    },
    yScrollChange (bol) {
      this.yIsShowScroll = bol
    },
    initTable () {
      this.tableWidth = this.$refs['scroll-table'].offsetWidth
    },
    initXscroll () {
      if (!this.isNeedXscroll.bol) {
        return
      }

      setTimeout(() => {
        this.HTML = document.getElementsByTagName('html')[0]
        this.warpper = this.$refs['xScroll-wrapper']
        this.warpperTh = this.$refs['warpperTh']
        this.warpperTb = this.$refs['warpperTb']
        this.warpperWidth = this.warpper.offsetWidth

        this.tbScroll = this.$refs['scroll-table-xScroll']
        this.tbScrollWidth = this.tbScroll.offsetWidth

        this.scrollMove = this.$refs['xScroll-move']
        this.scrollMove.style.width = `${Math.round(this.tableWidth / this.isNeedXscroll.width * this.tableWidth)}px`
      }, 20)
    },
    initColumns () {
      const thead = []
      const theadLeft = []
      const theadRight = []

      this.columns.map(item => {
        if (item.fixed === 'right') {
          theadRight.push(item)
        } else if (item.fixed === 'left') {
          theadLeft.push(item)
        } else {
          thead.push(item)
        }
      })

      this.thead = [...theadLeft, ...thead, ...theadRight]
      this.theadLeft = JSON.parse(JSON.stringify(this.thead))
      this.theadRight = [...theadRight, ...theadLeft, ...thead]
    },
    initData () {
      const tbody = JSON.parse(JSON.stringify(this.data))

      if (this.highlightRow) {
        tbody.map(item => {
          if (item['_highlight'] === undefined) {
            item['_highlight'] = false
          }
        })
      }

      tbody.map(item => {
        if (item['_checked'] === undefined) {
          item['_checked'] = false
        }
        item['_isHover'] = false
      })

      this.tbody = tbody

      if (this.tbody.length) {
        setTimeout(() => {
          this.onmouseWheel(this.$refs['xScroll-wrapper'], this.scrollWheel)
        }, 20)
      }
    },
    refreshScroll () {
      setTimeout(() => {
        this.$refs['scroll'].initScroll()
      }, 20)
    }
  }
}
</script>

<style lang="scss" scoped>
  .scroll-table {
    width: 100%;
    height: 100%;
    overflow: hidden;
    position: relative;
    .scroll-table-wrapper {
      width: 100%;
      position: relative;
      .scroll-tableThCenter {
        height: 32px;
        overflow: hidden;
        position: absolute;
        left: 0;
        top: 0;
      }
      .scroll-tableThLeft {
        overflow: hidden;
        position: absolute;
        left: 0;
        top: 0;
        box-shadow: 2px 0 6px -2px rgba(0, 0, 0, .2);
      }
      .scroll-tableThRight {
        overflow: hidden;
        position: absolute;
        right: 0;
        top: 0;
        box-shadow: -2px 0 6px -2px rgba(0, 0, 0, .2);
      }
      .scroll-tableTh {
        height: 32px;
        overflow: hidden;
        position: relative;
        .scroll-tableThCenter,
        .scroll-tableLeftTh,
        .scroll-tableRightTh {
          width: 100%;
          height: 32px;
          line-height: 32px;
          table-layout: fixed;
          > thead {
            > tr {
              width: 100%;
              > .th {
                padding: 0 5px;
                &.selection {
                  .ivu-checkbox-wrapper {
                    margin-right: 0;
                  }
                }
                &:nth-last-child(1) {
                  border-right: none !important;
                }
              }
            }
          }
        }
      }

      .scroll-tableTb {
        width: 100%;
        position: absolute;
        top: 32px;
        left: 0;
        overflow: hidden;
        > .no-data {
          width: 100%;
          height: 40px;
          text-align: center;
          line-height: 40px;
          color: white;
        }
        > .data {
          width: 100%;
          height: calc(100% - 32px);
          position: relative;
          .scroll-table-wrapper {
            position: relative;
            .scroll-tableTb-wrapper {
              overflow: hidden;
              position: relative;
              left: 0;
              top: 0;
            }
            .scroll-tableLeft-wrapper {
              overflow: hidden;
              position: absolute;
              left: 0;
              top: 0;
              box-shadow: 2px 0 6px -2px rgba(0, 0, 0, .2);
            }
            .scroll-tableRight-wrapper {
              position: absolute;
              right: 0;
              top: 0;
              box-shadow: -2px 0 6px -2px rgba(0, 0, 0, .2);
            }
            .scroll-tableTb-wrapper,
            .scroll-tableLeft-table,
            .scroll-tableRight-table {
              width: 100%;
              overflow: hidden;
              table-layout: fixed;
              > tbody {
                width: 100%;
                > .tb {
                  width: 100%;
                  height: 40px;
                  > .tb-item {
                    padding: 0 5px;
                    // line-height: 40px;
                    &.selection {
                      .ivu-checkbox-wrapper {
                        margin-right: 0;
                      }
                    }
                    &:nth-last-child(1) {
                      border-right: none !important;
                    }
                    > .text-wrapper {
                      text-overflow: ellipsis;
                      // overflow: hidden
                      word-break: break-all;
                    }
                  }
                  &:nth-last-child(1) {
                    border-bottom: none !important;
                  }
                }
              }
            }
          }
          .scroll-table-xScroll {
            width: 100%;
            position: relative;
            .xScroll-move {
              position: absolute;
              left: 0;
              top: 0;
              height: 100%;
              border-radius: 5px;
            }
          }
        }
      }
    }
    .scroll-tableLoading {
      position: absolute;
      left: 0;
      right: 0;
      top: 32px;
      bottom: 0;
      z-index: 999;
      overflow: hidden;
    }
  }
</style>
